package arithmetic.tree;

/**
 * 红黑树学习  红黑树的特性介绍：
          1.每个结点或是红的，或是黑的
          2.根节点是黑的
          3.每个叶结点是黑的
          4.如果一个结点是红的，则它的两个儿子都是黑的
          5.对每个结点，从该结点到其任何叶子节点的所有路径上包含相同数目的黑结点
 *
 *
 */
public class RBTree<T extends Comparable<T>> {

        private RBTNode<T> mRoot;    // 根结点

        private static final boolean RED   = false;
        private static final boolean BLACK = true;

        public class RBTNode<T extends Comparable<T>> {
            boolean color;        // 颜色: 红色=false  黑色=true
            T key;                // 关键字(键值)
            RBTNode<T> left;    // 左孩子
            RBTNode<T> right;    // 右孩子
            RBTNode<T> parent;    // 父结点

            public RBTNode(T key, boolean color, RBTNode<T> parent, RBTNode<T> left, RBTNode<T> right) {
                this.key = key;
                this.color = color;
                this.parent = parent;
                this.left = left;
                this.right = right;
            }

            public T getKey() {
                return key;
            }

            public String toString() {
                return ""+key+(this.color==RED?"(R)":"B");
            }
        }

        public RBTree() {
            mRoot=null;
        }

        private RBTNode<T> parentOf(RBTNode<T> node) {
            return node!=null ? node.parent : null;
        }
        private boolean colorOf(RBTNode<T> node) {
            return node!=null ? node.color : BLACK;
        }
        private boolean isRed(RBTNode<T> node) {
            return ((node!=null)&&(node.color==RED)) ? true : false;
        }
        private boolean isBlack(RBTNode<T> node) {
            return !isRed(node);
        }
        private void setBlack(RBTNode<T> node) {
            if (node!=null)
                node.color = BLACK;
        }
        private void setRed(RBTNode<T> node) {
            if (node!=null)
                node.color = RED;
        }
        private void setParent(RBTNode<T> node, RBTNode<T> parent) {
            if (node!=null)
                node.parent = parent;
        }
        private void setColor(RBTNode<T> node, boolean color) {
            if (node!=null)
                node.color = color;
        }

        /**
         * (递归实现)查找"红黑树x"中键值为key的节点
         */
        private RBTNode<T> search(RBTNode<T> x, T key) {
            if (x==null)
                return x;

            int cmp = key.compareTo(x.key);
            if (cmp < 0)
                return search(x.left, key);
            else if (cmp > 0)
                return search(x.right, key);
            else
                return x;
        }

        public RBTNode<T> search(T key) {
            return search(mRoot, key);
        }

        /**
         * (非递归实现)查找"红黑树x"中键值为key的节点
         */
        private RBTNode<T> iterativeSearch(RBTNode<T> x, T key) {
            while (x!=null) {
                int cmp = key.compareTo(x.key);

                if (cmp < 0)
                    x = x.left;
                else if (cmp > 0)
                    x = x.right;
                else
                    return x;
            }

            return x;
        }

        public RBTNode<T> iterativeSearch(T key) {
            return iterativeSearch(mRoot, key);
        }

        /**
         * 查找最小结点：返回tree为根结点的红黑树的最小结点。
         */
        private RBTNode<T> minimum(RBTNode<T> tree) {
            if (tree == null)
                return null;

            while(tree.left != null)
                tree = tree.left;
            return tree;
        }

        public T minimum() {
            RBTNode<T> p = minimum(mRoot);
            if (p != null)
                return p.key;

            return null;
        }

        /**
         * 查找最大结点：返回tree为根结点的红黑树的最大结点。
         */
        private RBTNode<T> maximum(RBTNode<T> tree) {
            if (tree == null)
                return null;

            while(tree.right != null)
                tree = tree.right;
            return tree;
        }

        public T maximum() {
            RBTNode<T> p = maximum(mRoot);
            if (p != null)
                return p.key;

            return null;
        }

        /**
         * 找结点(x)的后继结点。即，查找"红黑树中数据值大于该结点"的"最小结点"。
         */
        public RBTNode<T> successor(RBTNode<T> x) {
            // 如果x存在右孩子，则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
            if (x.right != null)
                return minimum(x.right);

            // 如果x没有右孩子。则x有以下两种可能：
            // (01) x是"一个左孩子"，则"x的后继结点"为 "它的父结点"。
            // (02) x是"一个右孩子"，则查找"x的最低的父结点，并且该父结点要具有左孩子"，找到的这个"最低的父结点"就是"x的后继结点"。
            RBTNode<T> y = x.parent;
            while ((y!=null) && (x==y.right)) {
                x = y;
                y = y.parent;
            }

            return y;
        }

        /**
         * 找结点(x)的前驱结点。即，查找"红黑树中数据值小于该结点"的"最大结点"。
         */
        public RBTNode<T> predecessor(RBTNode<T> x) {
            // 如果x存在左孩子，则"x的前驱结点"为 "以其左孩子为根的子树的最大结点"。
            if (x.left != null)
                return maximum(x.left);

            // 如果x没有左孩子。则x有以下两种可能：
            // (01) x是"一个右孩子"，则"x的前驱结点"为 "它的父结点"。
            // (01) x是"一个左孩子"，则查找"x的最低的父结点，并且该父结点要具有右孩子"，找到的这个"最低的父结点"就是"x的前驱结点"。
            RBTNode<T> y = x.parent;
            while ((y!=null) && (x==y.left)) {
                x = y;
                y = y.parent;
            }

            return y;
        }

        /**
         * 对红黑树的节点(x)进行左旋转
         * 左旋示意图(对节点x进行左旋)：
         *      px                              px
         *     /                               /
         *    x                               y
         *   /  \      --(左旋)-.           / \                #
         *  lx   y                          x  ry
         *     /   \                       /  \
         *    ly   ry                     lx  ly
         *
         *
         */
        private void leftRotate(RBTNode<T> x) {
            // 设置x的右孩子为y
            RBTNode<T> y = x.right;

            // 将 “y的左孩子” 设为 “x的右孩子”；
            // 如果y的左孩子非空，将 “x” 设为 “y的左孩子的父亲”
            x.right = y.left;
            if (y.left != null)
                y.left.parent = x;

            // 将 “x的父亲” 设为 “y的父亲”
            y.parent = x.parent;

            if (x.parent == null) {
                this.mRoot = y;            // 如果 “x的父亲” 是空节点，则将y设为根节点
            } else {
                if (x.parent.left == x)
                    x.parent.left = y;    // 如果 x是它父节点的左孩子，则将y设为“x的父节点的左孩子”
                else
                    x.parent.right = y;    // 如果 x是它父节点的左孩子，则将y设为“x的父节点的左孩子”
            }

            // 将 “x” 设为 “y的左孩子”
            y.left = x;
            // 将 “x的父节点” 设为 “y”
            x.parent = y;
        }

        /**
         * 对红黑树的节点(y)进行右旋转
         * 右旋示意图(对节点y进行左旋)：
         *            py                               py
         *           /                                /
         *          y                                x
         *         /  \      --(右旋)-.            /  \                     #
         *        x   ry                           lx   y
         *       / \                                   / \                   #
         *      lx  rx                                rx  ry
         *
         */
        private void rightRotate(RBTNode<T> y) {
            // 设置x是当前节点的左孩子。
            RBTNode<T> x = y.left;

            // 将 “x的右孩子” 设为 “y的左孩子”；
            // 如果"x的右孩子"不为空的话，将 “y” 设为 “x的右孩子的父亲”
            y.left = x.right;
            if (x.right != null)
                x.right.parent = y;

            // 将 “y的父亲” 设为 “x的父亲”
            x.parent = y.parent;

            if (y.parent == null) {
                this.mRoot = x;            // 如果 “y的父亲” 是空节点，则将x设为根节点
            } else {
                if (y == y.parent.right)
                    y.parent.right = x;    // 如果 y是它父节点的右孩子，则将x设为“y的父节点的右孩子”
                else
                    y.parent.left = x;    // (y是它父节点的左孩子) 将x设为“x的父节点的左孩子”
            }

            // 将 “y” 设为 “x的右孩子”
            x.right = y;

            // 将 “y的父节点” 设为 “x”
            y.parent = x;
        }

        /**
         * 红黑树插入修正函数
         * 在向红黑树中插入节点之后(失去平衡)，再调用该函数；
         * 目的是将它重新塑造成一颗红黑树。
         * 参数说明：
         *     node 插入的结点        // 对应《算法导论》中的z
         */
        private void insertFixUp(RBTNode<T> node) {
            RBTNode<T> parent, gparent;

            // 若“父节点存在，并且父节点的颜色是红色”
            while (((parent = parentOf(node))!=null) && isRed(parent)) {
                gparent = parentOf(parent);

                //若“父节点”是“祖父节点的左孩子”
                if (parent == gparent.left) {
                    // Case 1条件：叔叔节点是红色
                    RBTNode<T> uncle = gparent.right;
                    if ((uncle!=null) && isRed(uncle)) {
                        setBlack(uncle);
                        setBlack(parent);
                        setRed(gparent);
                        node = gparent;
                        continue;
                    }

                    // Case 2条件：叔叔是黑色，且当前节点是右孩子
                    if (parent.right == node) {
                        RBTNode<T> tmp;
                        leftRotate(parent);
                        tmp = parent;
                        parent = node;
                        node = tmp;
                    }

                    // Case 3条件：叔叔是黑色，且当前节点是左孩子。
                    setBlack(parent);
                    setRed(gparent);
                    rightRotate(gparent);
                } else {    //若“z的父节点”是“z的祖父节点的右孩子”
                    // Case 1条件：叔叔节点是红色
                    RBTNode<T> uncle = gparent.left;
                    if ((uncle!=null) && isRed(uncle)) {
                        setBlack(uncle);
                        setBlack(parent);
                        setRed(gparent);
                        node = gparent;
                        continue;
                    }

                    // Case 2条件：叔叔是黑色，且当前节点是左孩子
                    if (parent.left == node) {
                        RBTNode<T> tmp;
                        rightRotate(parent);
                        tmp = parent;
                        parent = node;
                        node = tmp;
                    }

                    // Case 3条件：叔叔是黑色，且当前节点是右孩子。
                    setBlack(parent);
                    setRed(gparent);
                    leftRotate(gparent);
                }
            }

            // 将根节点设为黑色
            setBlack(this.mRoot);
        }

        /*
         * 将结点插入到红黑树中
         *
         * 参数说明：
         *     node 插入的结点        // 对应《算法导论》中的node
         */
        private void insert(RBTNode<T> node) {
            int cmp;
            RBTNode<T> y = null;
            RBTNode<T> x = this.mRoot;

            // 1. 将红黑树当作一颗二叉查找树，将节点添加到二叉查找树中。
            while (x != null) {
                y = x;
                cmp = node.key.compareTo(x.key);
                if (cmp < 0)
                    x = x.left;
                else
                    x = x.right;
            }

            node.parent = y;
            if (y!=null) {
                cmp = node.key.compareTo(y.key);
                if (cmp < 0)
                    y.left = node;
                else
                    y.right = node;
            } else {
                this.mRoot = node;
            }

            // 2. 设置节点的颜色为红色
            node.color = RED;

            // 3. 将它重新修正为一颗二叉查找树
            insertFixUp(node);
        }

        /**
         * 新建结点(key)，并将其插入到红黑树中
         * 参数说明：
         *     key 插入结点的键值
         */
        public void insert(T key) {
            RBTNode<T> node=new RBTNode<T>(key,BLACK,null,null,null);
            // 如果新建结点失败，则返回。
            if (node != null)
                insert(node);
        }


        /**
         * 红黑树删除修正函数
         * 在从红黑树中删除插入节点之后(红黑树失去平衡)，再调用该函数；
         * 目的是将它重新塑造成一颗红黑树。
         * 参数说明：
         *     node 待修正的节点
         */
        private void removeFixUp(RBTNode<T> node, RBTNode<T> parent) {
            RBTNode<T> other;

            while ((node==null || isBlack(node)) && (node != this.mRoot)) {
                if (parent.left == node) {
                    other = parent.right;
                    if (isRed(other)) {
                        // Case 1: x的兄弟w是红色的
                        setBlack(other);
                        setRed(parent);
                        leftRotate(parent);
                        other = parent.right;
                    }
                    if ((other.left==null || isBlack(other.left)) &&
                            (other.right==null || isBlack(other.right))) {
                        // Case 2: x的兄弟w是黑色，且w的俩个孩子也都是黑色的
                        setRed(other);
                        node = parent;
                        parent = parentOf(node);
                    } else {
                        if (other.right==null || isBlack(other.right)) {
                            // Case 3: x的兄弟w是黑色的，并且w的左孩子是红色，右孩子为黑色。
                            setBlack(other.left);
                            setRed(other);
                            rightRotate(other);
                            other = parent.right;
                        }
                        // Case 4: x的兄弟w是黑色的；并且w的右孩子是红色的，左孩子任意颜色。
                        setColor(other, colorOf(parent));
                        setBlack(parent);
                        setBlack(other.right);
                        leftRotate(parent);
                        node = this.mRoot;
                        break;
                    }
                } else {
                    other = parent.left;
                    if (isRed(other)) {
                        // Case 1: x的兄弟w是红色的
                        setBlack(other);
                        setRed(parent);
                        rightRotate(parent);
                        other = parent.left;
                    }

                    if ((other.left==null || isBlack(other.left)) &&
                            (other.right==null || isBlack(other.right))) {
                        // Case 2: x的兄弟w是黑色，且w的俩个孩子也都是黑色的
                        setRed(other);
                        node = parent;
                        parent = parentOf(node);
                    } else {

                        if (other.left==null || isBlack(other.left)) {
                            // Case 3: x的兄弟w是黑色的，并且w的左孩子是红色，右孩子为黑色。
                            setBlack(other.right);
                            setRed(other);
                            leftRotate(other);
                            other = parent.left;
                        }

                        // Case 4: x的兄弟w是黑色的；并且w的右孩子是红色的，左孩子任意颜色。
                        setColor(other, colorOf(parent));
                        setBlack(parent);
                        setBlack(other.left);
                        rightRotate(parent);
                        node = this.mRoot;
                        break;
                    }
                }
            }

            if (node!=null)
                setBlack(node);
        }

        /**
         * 删除结点(node)，并返回被删除的结点
         * 参数说明：
         *     node 删除的结点
         */
        private void remove(RBTNode<T> node) {
            RBTNode<T> child, parent;
            boolean color;

            // 被删除节点的"左右孩子都不为空"的情况。
            if ( (node.left!=null) && (node.right!=null) ) {
                // 被删节点的后继节点。(称为"取代节点")
                // 用它来取代"被删节点"的位置，然后再将"被删节点"去掉。
                RBTNode<T> replace = node;

                // 获取后继节点
                replace = replace.right;
                while (replace.left != null)
                    replace = replace.left;

                // "node节点"不是根节点(只有根节点不存在父节点)
                if (parentOf(node)!=null) {
                    if (parentOf(node).left == node)
                        parentOf(node).left = replace;
                    else
                        parentOf(node).right = replace;
                } else {
                    // "node节点"是根节点，更新根节点。
                    this.mRoot = replace;
                }

                // child是"取代节点"的右孩子，也是需要"调整的节点"。
                // "取代节点"肯定不存在左孩子！因为它是一个后继节点。
                child = replace.right;
                parent = parentOf(replace);
                // 保存"取代节点"的颜色
                color = colorOf(replace);

                // "被删除节点"是"它的后继节点的父节点"
                if (parent == node) {
                    parent = replace;
                } else {
                    // child不为空
                    if (child!=null)
                        setParent(child, parent);
                    parent.left = child;

                    replace.right = node.right;
                    setParent(node.right, replace);
                }

                replace.parent = node.parent;
                replace.color = node.color;
                replace.left = node.left;
                node.left.parent = replace;

                if (color == BLACK)
                    removeFixUp(child, parent);

                node = null;
                return ;
            }

            if (node.left !=null) {
                child = node.left;
            } else {
                child = node.right;
            }

            parent = node.parent;
            // 保存"取代节点"的颜色
            color = node.color;

            if (child!=null)
                child.parent = parent;

            // "node节点"不是根节点
            if (parent!=null) {
                if (parent.left == node)
                    parent.left = child;
                else
                    parent.right = child;
            } else {
                this.mRoot = child;
            }

            if (color == BLACK)
                removeFixUp(child, parent);
            node = null;
        }

        /**
         * 删除结点(z)，并返回被删除的结点
         * 参数说明：
         *     tree 红黑树的根结点
         *     z 删除的结点
         */
        public void remove(T key) {
            RBTNode<T> node;
            if ((node = search(mRoot, key)) != null)
                remove(node);
        }

        /**
         * 销毁红黑树
         */
        private void destroy(RBTNode<T> tree) {
            if (tree==null)
                return ;
            if (tree.left != null)
                destroy(tree.left);
            if (tree.right != null)
                destroy(tree.right);
            tree=null;
        }

        public void clear() {
            destroy(mRoot);
            mRoot = null;
        }

        /**
         * 打印"红黑树"
         * key        -- 节点的键值
         * direction  --  0，表示该节点是根节点;
         *               -1，表示该节点是它的父结点的左孩子;
         *                1，表示该节点是它的父结点的右孩子。
         */
        private void print(RBTNode<T> tree, T key, int direction) {
            if(tree != null) {
                if(direction==0)    // tree是根节点
                    System.out.printf("%2d(B) is root\n", tree.key);
                else                // tree是分支节点
                    System.out.printf("%2d(%s) is %2d's %6s child\n", tree.key, isRed(tree)?"R":"B", key, direction==1?"right" : "left");

                print(tree.left, tree.key, -1);
                print(tree.right,tree.key,  1);
            }
        }

        public void print() {
            if (mRoot != null)
                print(mRoot, mRoot.key, 0);
        }
    }
